# _*_ coding: utf-8 _*_
"""
@ 时间    ：2024/10/23 17:19
@ 作者    ：旺财
@ 文件    ：02-2 股票涨跌预测模型-模型搭建与评估.py
@ 说明    ：
"""
import numpy as np
import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV

# 1.读取数据
df = pd.read_excel('股价数据.xlsx')
print(df.head())
# print(df.columns)

# 2.特征变量与目标变量提取
x = df[
    ['close', 'vol', 'close-open', 'MA5', 'MA10', 'high-low', 'RSI', 'MOM', 'EMA12', 'MACD', 'MACDsignal', 'MACDhist']
]
y = np.where(df['change'].shift(1) > 0, 1, -1)  # 1表示涨 -1表示跌

# 3.训练集测试集数据划分  由于股票预测的时间关联性,不能打破时间顺序,故不能用train_test_split
test_size = 0.2
split = int(x.shape[0] * (1 - test_size))
x_train, x_test, y_train, y_test = x[:split], x[split:], y[:split], y[split:]

# 4.模型搭建
model = RandomForestClassifier(max_depth=3, n_estimators=10, min_samples_leaf=10, random_state=1)
model.fit(x_train, y_train)

# 5.评估模型
# 查看预测与实际值
y_predict = model.predict(x_test)
a = pd.DataFrame()  # 创建一个空DataFrame
a['预测值'] = list(y_predict)
a['实际值'] = list(y_test)
print(a.head(10))

# 查看模型精准度
score = model.score(x_test, y_test)
print(f'模型精准度:{round(score*100, 2)}%')

# 6.分析数据特征的重要性
features = x.columns
importance = model.feature_importances_
b = pd.DataFrame()
b['特征'] = features
b['特征重要性'] = importance
b = b.sort_values('特征重要性', ascending=False)
print(b)

# 7.参数调优
# 指定分类器中参数的范围
parameters = {
    'n_estimators': [5, 10, 15, 20, 25],
    'max_depth': [5, 7, 9, 11, 13, 15],
    'min_samples_leaf': [5, 10, 15, 20, 25]
}
new_model = RandomForestClassifier(random_state=1)
grid_search = GridSearchCV(new_model, parameters, cv=6, scoring='accuracy')
grid_search.fit(x_train, y_train)
best_params = grid_search.best_params_
print(f'最优参数组合: {best_params}')

# 7.重新建立调优模型
model_new = RandomForestClassifier(
    max_depth=best_params['max_depth'],
    n_estimators=best_params['n_estimators'],
    min_samples_leaf=best_params['min_samples_leaf'],
    random_state=1)
model_new.fit(x_train, y_train)

# 8.打印提升
score_new = model_new.score(x_test, y_test)
print(f'调优后准确率提升: {round(score*100, 2)}% --> {round(score_new*100, 2)}%')
